package co.edu.usbcali.presentation.backingBeans;

import co.edu.usbcali.exceptions.*;
import co.edu.usbcali.parcial3.*;
import co.edu.usbcali.parcial3.dto.FacturaDTO;
import co.edu.usbcali.presentation.businessDelegate.BusinessDelegatorView;
import co.edu.usbcali.utilities.*;

import com.icesoft.faces.async.render.RenderManager;
import com.icesoft.faces.async.render.Renderable;
import com.icesoft.faces.component.ext.HtmlCommandButton;
import com.icesoft.faces.component.ext.HtmlInputText;
import com.icesoft.faces.component.ext.HtmlSelectOneListbox;
import com.icesoft.faces.component.ext.HtmlSelectOneMenu;
import com.icesoft.faces.component.ext.RowSelectorEvent;
import com.icesoft.faces.component.selectinputdate.SelectInputDate;
import com.icesoft.faces.context.DisposableBean;
import com.icesoft.faces.webapp.xmlhttp.FatalRenderingException;
import com.icesoft.faces.webapp.xmlhttp.PersistentFacesState;
import com.icesoft.faces.webapp.xmlhttp.RenderingException;
import com.icesoft.faces.webapp.xmlhttp.TransientRenderingException;
import com.sun.org.apache.xalan.internal.xsltc.compiler.sym;

import java.math.BigDecimal;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.TimeZone;
import java.util.Vector;

import javax.faces.event.ActionEvent;
import javax.faces.event.ValueChangeEvent;
import javax.faces.model.DataModel;
import javax.faces.model.SelectItem;

/**
 * 
 * 
 * @author Zathura Code Generator http://code.google.com/p/zathura
 * 
 */
public class FacturaView extends DataSource implements Renderable,
		DisposableBean {
	private HtmlInputText txtFactValor;
	private HtmlInputText txtUsuCodigo_Usuario;
	private HtmlInputText txtFactNumero;
	private SelectInputDate txtFactFechaEmision;
	private SelectInputDate txtFactFechaLimite;
	private HtmlCommandButton btnSave;
	private HtmlCommandButton btnModify;
	private HtmlCommandButton btnDelete;
	private HtmlCommandButton btnClear;
	private HtmlCommandButton btnPagar;
	private boolean renderDataTable;
	private boolean flag = true;
	private RenderManager renderManager;
	private PersistentFacesState state = PersistentFacesState.getInstance();
	private List<Factura> factura;
	private List<FacturaDTO> facturaDTO;
	private List<Factura> facturaEncontradas = new ArrayList<Factura>();
	private List<Factura> facturaSelecconadas = new ArrayList<Factura>();
	private boolean rowSelected = false;
	private HtmlInputText suma = new HtmlInputText();
	Long total = 0l;
	private HtmlSelectOneMenu cmbTipos;
	private List<SelectItem> items;

	public FacturaView() {
		super("");
	}

	public String action_volver() {
		facturaSelecconadas.clear();
		total = 0l;
		return "irmenu";

	}

	// Metodo que selecciona una celda en la tabla...
	public void seleccionFila(RowSelectorEvent event) {
		boolean esta = true;
		int posicion = -1;
		// Facutra seleccionada en la tabla...
		Factura factura = facturaEncontradas.get(event.getRow());
		if (facturaSelecconadas.size() == 0) {
			facturaSelecconadas.add(factura);
			total += factura.getFactValor().intValue();
		} else {
			// se recorre las facturas seleccionadas buscando la factura que le
			// di clic
			for (int i = 0; i < facturaSelecconadas.size(); i++) {
				// Busqueda de facturas en la lista de seleccionadas
				Factura facturaSelec = facturaSelecconadas.get(i);
				if (facturaSelec.getFactNumero()
						.equals(factura.getFactNumero())) {
					posicion = i;
					esta = true;
					break;
				} else {
					esta = false;
				}
			}

			if (esta) {
				total -= facturaSelecconadas.get(posicion).getFactValor()
						.intValue();
				facturaSelecconadas.remove(posicion);

			} else {
				total += factura.getFactValor().intValue();
				facturaSelecconadas.add(factura);
			}
		}
	}

	// Metodoque paga las facturas...
	public void action_pagar() {
		try {

			Date fecha = new Date();
			Usuario u = (Usuario) FacesUtils.getSession().getAttribute(
					"usuario");
			Long codCom = 1 + BusinessDelegatorView
					.findTotalNumberComprobante();
			BusinessDelegatorView.saveComprobante(codCom + "", fecha, total, u
					.getUsuCodigo());
			for (int i = 0; i < facturaSelecconadas.size(); i++) {
				BusinessDelegatorView.saveFacturaPaga(null, codCom + "",
						facturaSelecconadas.get(i).getFactNumero());
			}
			FacesUtils.addInfoMessage("Pago Realizado Con Exito");
			btnPagar.setDisabled(true);
		} catch (Exception e) {
			FacesUtils.addErrorMessage(e.getMessage());
		}
	}

	public String action_clear() {
		txtFactValor.setValue(null);
		txtFactValor.setDisabled(true);
		txtUsuCodigo_Usuario.setValue(null);
		txtUsuCodigo_Usuario.setDisabled(true);
		txtFactFechaEmision.setValue(null);
		txtFactFechaEmision.setDisabled(true);
		txtFactFechaLimite.setValue(null);
		txtFactFechaLimite.setDisabled(true);
		txtFactNumero.setValue(null);
		txtFactNumero.setDisabled(false);
		btnSave.setDisabled(true);
		btnDelete.setDisabled(true);
		btnModify.setDisabled(true);
		btnClear.setDisabled(false);

		return "";
	}

	public void listener_txtId(ValueChangeEvent event) {
		if ((event.getNewValue() != null) && !event.getNewValue().equals("")) {
			Factura entity = null;

			try {
				String factNumero = new String(txtFactNumero.getValue()
						.toString());
				entity = BusinessDelegatorView.getFactura(factNumero);
			} catch (Exception e) {
				// TODO: handle exception
			}

			if (entity == null) {
				txtFactValor.setDisabled(false);
				txtUsuCodigo_Usuario.setDisabled(false);
				txtFactFechaEmision.setDisabled(false);
				txtFactFechaLimite.setDisabled(false);
				txtFactNumero.setDisabled(false);
				btnSave.setDisabled(false);
				btnDelete.setDisabled(true);
				btnModify.setDisabled(true);
				btnClear.setDisabled(false);
			} else {
				txtFactFechaEmision.setValue(entity.getFactFechaEmision());
				txtFactFechaEmision.setDisabled(false);
				txtFactFechaLimite.setValue(entity.getFactFechaLimite());
				txtFactFechaLimite.setDisabled(false);
				txtFactValor.setValue(entity.getFactValor());
				txtFactValor.setDisabled(false);
				txtUsuCodigo_Usuario.setValue(entity.getUsuario()
						.getUsuCodigo());
				txtUsuCodigo_Usuario.setDisabled(false);
				txtFactNumero.setValue(entity.getFactNumero());
				txtFactNumero.setDisabled(true);
				btnSave.setDisabled(true);
				btnDelete.setDisabled(false);
				btnModify.setDisabled(false);
				btnClear.setDisabled(false);
			}
		}
	}

	public String action_save() {
		try {
			BusinessDelegatorView.saveFactura(FacesUtils
					.checkDate(txtFactFechaEmision), FacesUtils
					.checkDate(txtFactFechaLimite), FacesUtils
					.checkString(txtFactNumero), FacesUtils
					.checkLong(txtFactValor), FacesUtils
					.checkString(txtUsuCodigo_Usuario));
			FacesUtils.addInfoMessage(ZMessManager.ENTITY_SUCCESFULLYSAVED);
			action_clear();
		} catch (Exception e) {
			FacesUtils.addErrorMessage(e.getMessage());
		}

		return "";
	}

	public String action_delete() {
		try {
			BusinessDelegatorView.deleteFactura(FacesUtils
					.checkString(txtFactNumero));
			FacesUtils.addInfoMessage(ZMessManager.ENTITY_SUCCESFULLYDELETED);
			action_clear();
		} catch (Exception e) {
			FacesUtils.addErrorMessage(e.getMessage());
		}

		return "";
	}

	public String action_modify() {
		try {
			BusinessDelegatorView.updateFactura(FacesUtils
					.checkDate(txtFactFechaEmision), FacesUtils
					.checkDate(txtFactFechaLimite), FacesUtils
					.checkString(txtFactNumero), FacesUtils
					.checkLong(txtFactValor), FacesUtils
					.checkString(txtUsuCodigo_Usuario));
			FacesUtils.addInfoMessage(ZMessManager.ENTITY_SUCCESFULLYMODIFIED);
			action_clear();
		} catch (Exception e) {
			FacesUtils.addErrorMessage(e.getMessage());
		}

		return "";
	}

	public String action_modifyWitDTO(Date factFechaEmision,
			Date factFechaLimite, String factNumero, Long factValor,
			String usuCodigo_Usuario) throws Exception {
		try {
			BusinessDelegatorView.updateFactura(factFechaEmision,
					factFechaLimite, factNumero, factValor, usuCodigo_Usuario);
			renderManager.getOnDemandRenderer("FacturaView").requestRender();
			FacesUtils.addInfoMessage(ZMessManager.ENTITY_SUCCESFULLYMODIFIED);
		} catch (Exception e) {
			// renderManager.getOnDemandRenderer("FacturaView").requestRender();
			FacesUtils.addErrorMessage(e.getMessage());
			throw e;
		}

		return "";
	}

	public List<Factura> getFactura() {
		if (flag) {
			try {
				factura = BusinessDelegatorView.getFactura();
				flag = false;
			} catch (Exception e) {
				flag = true;
				FacesUtils.addErrorMessage(e.getMessage());
			}
		}

		return factura;
	}

	public boolean isFlag() {
		return flag;
	}

	public void setFactura(List<Factura> factura) {
		this.factura = factura;
	}

	public boolean isRenderDataTable() {
		try {
			if (flag) {
				if (BusinessDelegatorView.findTotalNumberFactura() > 0) {
					renderDataTable = true;
				} else {
					renderDataTable = false;
				}
			}

			flag = false;
		} catch (Exception e) {
			renderDataTable = false;
			e.printStackTrace();
		}

		return renderDataTable;
	}

	public DataModel getData() {
		state = PersistentFacesState.getInstance();

		if (onePageDataModel == null) {
			onePageDataModel = new LocalDataModel(pageSize);
		}

		return onePageDataModel;
	}

	/**
	 * This is where the Object data is retrieved from the database and returned
	 * as a list of objects for display in the UI.
	 */
	private DataPage<Factura> getDataPage(int startRow, int pageSize) {
		// Retrieve the total number of objects from the database. This
		// number is required by the DataPage object so the paginator will know
		// the relative location of the page data.
		int totalNumberFactura = 0;

		try {
			totalNumberFactura = BusinessDelegatorView.findTotalNumberFactura()
					.intValue();
		} catch (Exception e) {
			FacesUtils.addErrorMessage(e.getMessage());
		}

		// Calculate indices to be displayed in the ui.
		int endIndex = startRow + pageSize;

		if (endIndex > totalNumberFactura) {
			endIndex = totalNumberFactura;
		}

		try {
			factura = BusinessDelegatorView.findPageFactura(sortColumnName,
					sortAscending, startRow, endIndex - startRow);

			// Remove this Renderable from the existing render groups.
			// leaveRenderGroups();
		} catch (Exception e) {
			FacesUtils.addErrorMessage(e.getMessage());
		}

		// Add this Renderable to the new render groups.
		// joinRenderGroups();
		// Reset the dirtyData flag.
		onePageDataModel.setDirtyData(false);
		// This is required when using Hibernate. If the SessionManager is not
		// cleared or closed objects are cached and stale objects will show up
		// in the table.
		// This way, the detached objects are reread from the database.
		// This call is not required with Hibernate, which uses a Query Hint
		// to clear the l2 cache in the DAO.
		flag = true;

		return new DataPage<Factura>(totalNumberFactura, startRow, factura);
	}

	public DataModel getDataDTO() {
		state = PersistentFacesState.getInstance();

		if (onePageDataModel == null) {
			onePageDataModel = new LocalDataModelDTO(pageSize);
		}

		return onePageDataModel;
	}

	/**
	 * This is where the Object data is retrieved from the database and returned
	 * as a list of objects for display in the UI.
	 */
	private DataPage<FacturaDTO> getDataPageDTO(int startRow, int pageSize) {
		// Retrieve the total number of objects from the database. This
		// number is required by the DataPage object so the paginator will know
		// the relative location of the page data.
		int totalNumberFactura = 0;

		try {
			totalNumberFactura = BusinessDelegatorView.findTotalNumberFactura()
					.intValue();
		} catch (Exception e) {
			FacesUtils.addErrorMessage(e.getMessage());
		}

		// Calculate indices to be displayed in the ui.
		int endIndex = startRow + pageSize;

		if (endIndex > totalNumberFactura) {
			endIndex = totalNumberFactura;
		}

		try {
			factura = BusinessDelegatorView.findPageFactura(sortColumnName,
					sortAscending, startRow, endIndex - startRow);

			if (Utilities.validationsList(factura)) {
				facturaDTO = new ArrayList<FacturaDTO>();

				for (Factura facturaTmp : factura) {
					FacturaDTO facturaDTO2 = new FacturaDTO();
					facturaDTO2.setFactNumero(facturaTmp.getFactNumero()
							.toString());
					facturaDTO2.setFactFechaEmision(facturaTmp
							.getFactFechaEmision());
					facturaDTO2.setFactFechaLimite(facturaTmp
							.getFactFechaLimite());
					facturaDTO2
							.setFactValor((facturaTmp.getFactValor() != null) ? facturaTmp
									.getFactValor().toString()
									: null);
					facturaDTO2.setUsuCodigo_Usuario((facturaTmp.getUsuario()
							.getUsuCodigo() != null) ? facturaTmp.getUsuario()
							.getUsuCodigo().toString() : null);
					facturaDTO2.setFactura(facturaTmp);
					facturaDTO2.setFacturaView(this);
					facturaDTO.add(facturaDTO2);
				}
			}

			// Remove this Renderable from the existing render groups.
			leaveRenderGroups();
		} catch (Exception e) {
			FacesUtils.addErrorMessage(e.getMessage());
		}

		// Add this Renderable to the new render groups.
		joinRenderGroups();
		// Reset the dirtyData flag.
		onePageDataModel.setDirtyData(false);
		// This is required when using Hibernate. If the SessionManager is not
		// cleared or closed objects are cached and stale objects will show up
		// in the table.
		// This way, the detached objects are reread from the database.
		// This call is not required with Hibernate, which uses a Query Hint
		// to clear the l2 cache in the DAO.
		flag = true;

		return new DataPage<FacturaDTO>(totalNumberFactura, startRow,
				facturaDTO);
	}

	protected boolean isDefaultAscending(String sortColumn) {
		return true;
	}

	/**
	 * This method is called when a render call is made from the server. Render
	 * calls are only made to views containing an updated record. The data is
	 * marked as dirty to trigger a fetch of the updated record from the
	 * database before rendering takes place.
	 */
	public PersistentFacesState getState() {
		onePageDataModel.setDirtyData();

		return state;
	}

	/**
	 * This method is called from faces-config.xml with each new session.
	 */
	public void setRenderManager(RenderManager renderManager) {
		this.renderManager = renderManager;
	}

	public void renderingException(RenderingException arg0) {
		if (arg0 instanceof TransientRenderingException) {
		} else if (arg0 instanceof FatalRenderingException) {
			// Remove from existing Customer render groups.
			leaveRenderGroups();
		}
	}

	/**
	 * Remove this Renderable from existing uiCustomerBeans render groups.
	 * OnDemandRenderers are named/created using the underlying Customer Number.
	 */
	private void leaveRenderGroups() {
		if (Utilities.validationsList(facturaDTO)) {
			for (FacturaDTO facturaTmp : facturaDTO) {
				renderManager.getOnDemandRenderer("FacturaView").remove(this);
			}
		}
	}

	/**
	 * Add this Renderable to the new uiCustomerBeans render groups.
	 * OnDemandRenderers are named/created using the underlying Customer Number.
	 */
	private void joinRenderGroups() {
		if (Utilities.validationsList(facturaDTO)) {
			for (FacturaDTO facturaTmp : facturaDTO) {
				renderManager.getOnDemandRenderer("FacturaView").add(this);
			}
		}
	}

	public void dispose() throws Exception {
	}

	public RenderManager getRenderManager() {
		return renderManager;
	}

	public void setState(PersistentFacesState state) {
		this.state = state;
	}

	public HtmlInputText getTxtFactValor() {
		return txtFactValor;
	}

	public void setTxtFactValor(HtmlInputText txtFactValor) {
		this.txtFactValor = txtFactValor;
	}

	public HtmlInputText getTxtUsuCodigo_Usuario() {
		return txtUsuCodigo_Usuario;
	}

	public void setTxtUsuCodigo_Usuario(HtmlInputText txtUsuCodigo_Usuario) {
		this.txtUsuCodigo_Usuario = txtUsuCodigo_Usuario;
	}

	public SelectInputDate getTxtFactFechaEmision() {
		return txtFactFechaEmision;
	}

	public void setTxtFactFechaEmision(SelectInputDate txtFactFechaEmision) {
		this.txtFactFechaEmision = txtFactFechaEmision;
	}

	public SelectInputDate getTxtFactFechaLimite() {
		return txtFactFechaLimite;
	}

	public void setTxtFactFechaLimite(SelectInputDate txtFactFechaLimite) {
		this.txtFactFechaLimite = txtFactFechaLimite;
	}

	public HtmlInputText getTxtFactNumero() {
		return txtFactNumero;
	}

	public void setTxtFactNumero(HtmlInputText txtFactNumero) {
		this.txtFactNumero = txtFactNumero;
	}

	public HtmlCommandButton getBtnSave() {
		return btnSave;
	}

	public void setBtnSave(HtmlCommandButton btnSave) {
		this.btnSave = btnSave;
	}

	public HtmlCommandButton getBtnModify() {
		return btnModify;
	}

	public void setBtnModify(HtmlCommandButton btnModify) {
		this.btnModify = btnModify;
	}

	public HtmlCommandButton getBtnDelete() {
		return btnDelete;
	}

	public void setBtnDelete(HtmlCommandButton btnDelete) {
		this.btnDelete = btnDelete;
	}

	public HtmlCommandButton getBtnClear() {
		return btnClear;
	}

	public void setBtnClear(HtmlCommandButton btnClear) {
		this.btnClear = btnClear;
	}

	public void setRenderDataTable(boolean renderDataTable) {
		this.renderDataTable = renderDataTable;
	}

	public void setFlag(boolean flag) {
		this.flag = flag;
	}

	public List<FacturaDTO> getFacturaDTO() {
		return facturaDTO;
	}

	public void setFacturaDTO(List<FacturaDTO> facturaDTO) {
		this.facturaDTO = facturaDTO;
	}

	public TimeZone getTimeZone() {
		return java.util.TimeZone.getDefault();
	}

	public HtmlSelectOneMenu getCmbTipos() {

		items = new ArrayList<SelectItem>();
		items.add(new SelectItem("0", "T.C"));
		items.add(new SelectItem("1", "Cheque"));
		items.add(new SelectItem("2", "Efectivo"));
		return cmbTipos;
	}

	public void setCmbTipos(HtmlSelectOneMenu cmbTipos) {
		this.cmbTipos = cmbTipos;
	}

	public HtmlCommandButton getBtnPagar() {
		return btnPagar;
	}

	public void setBtnPagar(HtmlCommandButton btnPagar) {
		this.btnPagar = btnPagar;
	}

	public List<SelectItem> getItems() {
		return items;
	}

	public void setItems(List<SelectItem> items) {
		this.items = items;
	}

	public Long getTotal() {
		return total;
	}

	public void setTotal(Long total) {
		this.total = total;
	}

	public HtmlInputText getSuma() {
		suma.setValue(total);
		return suma;
	}

	public void setSuma(HtmlInputText suma) {
		this.suma = suma;
	}

	public boolean isRowSelected() {
		return rowSelected;
	}

	public void setRowSelected(boolean rowSelected) {
		this.rowSelected = rowSelected;
	}

	public List<Factura> getFacturaSelecconadas() {
		return facturaSelecconadas;
	}

	public void setFacturaSelecconadas(List<Factura> facturaSelecconadas) {
		this.facturaSelecconadas = facturaSelecconadas;
	}

	public List<Factura> getFacturaEncontradas() {
		try {
			Usuario u = (Usuario) FacesUtils.getSession().getAttribute("usuario");
			facturaEncontradas = BusinessDelegatorView.getFacturaPorPagar(u.getUsuCodigo());
		} catch (Exception e) {
			FacesUtils.addErrorMessage(e.getMessage());
		}

		return facturaEncontradas;
	}

	public void setFacturaEncontradas(List<Factura> facturaEncontradas) {
		this.facturaEncontradas = facturaEncontradas;
	}

	/**
	 * A special type of JSF DataModel to allow a datatable and datapaginator to
	 * page through a large set of data without having to hold the entire set of
	 * data in memory at once. Any time a managed bean wants to avoid holding an
	 * entire dataset, the managed bean declares this inner class which extends
	 * PagedListDataModel and implements the fetchData method. fetchData is
	 * called as needed when the table requires data that isn't available in the
	 * current data page held by this object. This requires the managed bean
	 * (and in general the business method that the managed bean uses) to
	 * provide the data wrapped in a DataPage object that provides info on the
	 * full size of the dataset.
	 */
	private class LocalDataModel extends PagedListDataModel {
		public LocalDataModel(int pageSize) {
			super(pageSize);
		}

		public DataPage<Factura> fetchPage(int startRow, int pageSize) {
			// call enclosing managed bean method to fetch the data
			return getDataPage(startRow, pageSize);
		}
	}

	private class LocalDataModelDTO extends PagedListDataModel {
		public LocalDataModelDTO(int pageSize) {
			super(pageSize);
		}

		public DataPage<FacturaDTO> fetchPage(int startRow, int pageSize) {
			// call enclosing managed bean method to fetch the data
			return getDataPageDTO(startRow, pageSize);
		}
	}

	public String action_irFacturasPorPagar() {
		getFacturaEncontradas();
		if (facturaEncontradas == null || facturaEncontradas.size() == 0) {
			FacesUtils.addErrorMessage("No Tiene Facturas Pendientes de Pago");
			return "";
		}
		return "goFacturas";
	}
}
